
#include "fast-math.h"

/**
 * @brief       利用泰勒级数计算sin(x)的近似值
 * @param       x: 计算的弧度
 * @param       n: 泰勒级数的项数
 * @retval      sin函数数值
 */
float fast_sin(float x, int n)
{
    float term = x;    // 第一项是 x
    float sin_x = 0.0; // sin(x)的累加结果

    for (int i = 1; i <= n; i++)
    {
        sin_x += term;                            // 累加当前项
        term *= -x * x / ((2 * i) * (2 * i + 1)); // 计算下一项
    }

    return sin_x;
}

/**
 * @brief       利用反正切麦克劳林展开式求解arctan
 * @param       x: 计算的数值，范围（-1，1）
 * @retval      arctan函数求解的弧度
 * @note        阶数越高，值越准确   70°以内是准确的
 */
float arctan(float x)
{
    float t = x;
    float result = 0;
    float X2 = x * x;
    unsigned char cnt = 1;

    do
    {
        result += t / ((cnt << 1) - 1);
        t = -t;
        t *= X2;
        cnt++;
    } while (cnt <= 6); // 仅计算前6项

    return result;
}

/**
 * @brief       快速计算平方根倒数数值
 * @param       x: 计算的数
 * @retval      目标数值
 */
float Q_rsqrt(float number)
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y = number;
    i = *(long *)&y;
    i = 0x5f3759df - (i >> 1);
    y = *(float *)&i;
    y = y * (threehalfs - (x2 * y * y)); // 1st iteration （第一次牛顿迭代）
    return y;
}

float fast_exp(float y)
{
    float d;
    *((short *)&d + 0) = 0;
    *((short *)&d + 1) = (short)(184 * y + (16256 - 7));
    return d;
}

#define POW223 8388608.0 // 2^23
float fast_log2(float x)
{
    long *a;
    double o;
    a = (long *)&x; // 强制的位转换
    o = (double)*a;
    // ???实际证明那个0.04几的值误差非常大....
    o = o / POW223 - 126.928071372;
    return (float)o;
}

#define log_2 0.69314718055994530941723212145818
float fast_log(float x)
{
    return fast_log2(x) * log_2;
}
